// 带计数器的DUT：counter_dut.sv
module cadder (
    input           [15:0]      augend,
    input           [15:0]      addend,
    output          [16:0]      result
);

    assign result = {1'b0, augend} + {1'b0, addend};

endmodule

module counter_dut (
    input                   clk,
    input                   rst_n,
    input                   bus_cmd_valid,
    input                   bus_op,
    input       [15:0]      bus_addr,
    input       [15:0]      bus_wdata,
    input       [7:0]       rx_d,
    input                   rx_dv,

    output reg  [15:0]      bus_rdata,
    output reg  [7:0]       tx_d,
    output reg              tx_en
);

    reg invert;

    always @ (posedge clk) begin
        if (!rst_n) begin
            tx_d <= 8'b0;
            tx_en <= 1'b0;
        end
        else if (invert) begin
            tx_d <= ~rx_d;
            tx_en <= rx_dv;
        end
        else begin
            tx_d <= rx_d;
            tx_en <= rx_dv;
        end
    end

    reg [31:0] counter;
    wire [16:0] counter_low_result;
    wire [16:0] counter_high_result;

    cadder low_adder (
        .augend         (counter[15:0]),
        .addend         (16'h1),
        .result         (counter_low_result)
    );

    cadder high_adder (
        .augend         (counter[31:16]),
        .addend         (16'h1),
        .result         (counter_high_result)
    );

    always @ (posedge clk) begin
        if (!rst_n) begin
            counter[15:0] <= 16'h0;
        end
        else if (rx_dv) begin
            counter[15:0] <= counter_low_result[15:0];
        end
    end

    always @ (posedge clk) begin
        if (!rst_n) begin
            counter[31:16] <= 16'h0;
        end
        else if (counter_low_result[16]) begin
            counter[31:16] <= counter_high_result[15:0];
        end
    end

    always @ (posedge clk) begin
        if (!rst_n) begin
            invert <= 1'b0;
        end
        else if (bus_cmd_valid && bus_op) begin
            case(bus_addr)
                16'h5: begin
                    if (bus_wdata[0] == 1'b1) begin
                        counter <= 32'h0;
                    end
                end
                16'h6: begin
                    if (bus_wdata[0] == 1'b1) begin
                        counter <= 32'h0;
                    end
                end
                16'h9: begin
                    invert <= bus_wdata[0];
                end
                default: begin
                end
            endcase
        end
    end

    always @ (posedge clk) begin
        if (!rst_n) begin
            bus_rdata <= 16'b0;
        end
        else if (bus_cmd_valid && !bus_op) begin
            case(bus_addr)
                16'h5: begin
                    bus_rdata <= counter[31:16];
                end
                16'h6: begin
                    bus_rdata <= counter[15:0];
                end
                16'h9: begin
                    bus_rdata <= {15'b0, invert};
                end
                default: begin
                    bus_rdata < 16'b0;
                end
            endcase
        end
    end

endmodule